/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.cmp.player.controls;

import com.cmp.core.Main;
import static com.cmp.core.constants.InputUIDConstants.*;
import com.cmp.logging.LoggerControl;
import com.jme3.input.InputManager;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.AnalogListener;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
import com.jme3.renderer.Camera;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort;
import com.jme3.scene.Spatial;
import com.jme3.scene.control.AbstractControl;
import com.jme3.scene.control.Control;
import static java.util.logging.Level.*;
import java.util.logging.Logger;

/**
 * Gets input and writes sets the commands for the spatial.
 * other controls will react to it.
 *
 * @author krummer
 */
public class InputControl extends AbstractControl implements ActionListener, AnalogListener {

    private InputManager inputManager;
    private static final Logger logger = Logger.getLogger(InputControl.class.getName());

    static {
        logger.addHandler(LoggerControl.getConsoleHandler());
        logger.setLevel(FINEST);
    }

    @SuppressWarnings("LeakingThisInConstructor")
    public InputControl(InputManager input) {
        this.inputManager = input;
        this.inputManager.addListener(this,
                new String[]{ABILITY_BUTTON_UID, ATTACK_BUTTON_UID, UP_BUTTON_UID, DOWN_BUTTON_UID, LEFT_BUTTON_UID, RIGHT_BUTTON_UID, JUMP_BUTTON_UID, VIEW_DIRECTION_UPDATE_UID});
    }

    /**
     * Add movement state data to player node.
     *
     * @param spatial player node.
     */
    @Override
    public void setSpatial(Spatial spatial) {
        super.setSpatial(spatial);
        
        //init as false, because no movement at beginning. duh
        spatial.setUserData(UP_BUTTON_UID, false);
        spatial.setUserData(DOWN_BUTTON_UID, false);
        spatial.setUserData(LEFT_BUTTON_UID, false);
        spatial.setUserData(RIGHT_BUTTON_UID, false);
        spatial.setUserData(JUMP_BUTTON_UID, false);
        spatial.setUserData(ATTACK_BUTTON_UID, false);
        spatial.setUserData(ABILITY_BUTTON_UID, false);
        spatial.setUserData(VIEW_DIRECTION_UPDATE_UID, false);
        
        this.setLocked(false);
    }

    @Override
    protected void controlUpdate(float tpf) {
        
        //rotate to cursor
        //if (hasViewDirectionChanged) {            
            findCursorPositionInPlayerPlane();
            //rest flag
            //spatial.setUserData(VIEW_DIRECTION_UPDATE_UID, false);
            //set y of contact point to spatial height to avoid nodding of mesh
            /*contact.setY(body.getPhysicsLocation().getY());
            //reorientate spatial
            spatial.lookAt(contact, Vector3f.UNIT_Y);
            //reorientate physics
            if (body.getMotionState().isApplyPhysicsLocal()) {
                body.setPhysicsRotation(spatial.getLocalRotation());
            } else {
                body.setPhysicsRotation(spatial.getWorldRotation());
            }
            logger.log(FINEST, "contact = {0}", contact);*/
        //}
    }
    
    public void setLocked(boolean lock) {
        super.getSpatial().setUserData("lockedInput", lock);
    }
    
    public boolean getLocked() {
        return super.getSpatial().getUserData("lockedInput");
    }

    private void findCursorPositionInPlayerPlane() {
        //TODO: camera will be elsewhere at some point.
        Camera cam = Main.app.getCamera();
        Vector2f cursorPosi2D = inputManager.getCursorPosition();
        Vector3f cursorPosi3D = cam.getWorldCoordinates(cursorPosi2D, 0);
        Vector3f dir = cursorPosi3D.subtract(cam.getLocation());
        Vector3f positionOfSpatial = spatial.getWorldTranslation();
        Vector3f normal = Vector3f.UNIT_Y;
        float distance = positionOfSpatial.subtract(cursorPosi3D).dot(normal) / dir.dot(normal);
        super.getSpatial().setUserData(CURSOR_POS_UID, cursorPosi3D.add(dir.mult(distance)));
    }

    @Override
    protected void controlRender(RenderManager rm, ViewPort vp) {
    }

    public void onAction(String name, boolean isPressed, float tpf) {
        //save inputs for state handling
        if(this.getLocked()) {
            return;
        }
        
        getSpatial().setUserData(name, isPressed);
    }

    public void onAnalog(String name, float value, float tpf) {
        if (name.equals(VIEW_DIRECTION_UPDATE_UID)) {
            //getSpatial().setUserData(name, true);
        }
    }

    public Control cloneForSpatial(Spatial spatial) {
        throw new UnsupportedOperationException("Not supported yet.");
    }
}
